package multithread.pool;

import error.MyExceptionEnum;
import error.MyProjectException;
import lombok.val;

import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author: zhangrongqing
 * @Date: 2019/12/19 18:53
 */
public class ConnectionPool {
    LinkedList<Connection> connections = new LinkedList<>();
    Lock lock;
    Condition condition;
    long timeout;
    private final static long DefaultConnectTimeOut = 1000; //默认超时时间1S

    public ConnectionPool(int initialSize) {
        if(initialSize < 0 ){
            throw new MyProjectException(MyExceptionEnum.ConnectionPoolError.code,MyExceptionEnum.ConnectionPoolError.msg);
        }
        for (int i = 0; i < initialSize; i++) {
            connections.add(new Connection());
        }
        lock = new ReentrantLock();
        condition = lock.newCondition();
        timeout = DefaultConnectTimeOut;
    }

    public Connection getConnection(){
        Connection connection = null;
        try{
            lock.lock();
            if(connections.size() <= 0){
                condition.await(timeout, TimeUnit.MILLISECONDS);  //等待超时时间
                if(connections.isEmpty()){
                    System.out.println("Get Connnection is timeout");
                    return connection;         //超时等待
                }
            }
            connection = connections.removeLast();
            System.out.println(connection + "getted");
            return connection;
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        return connection;
    }

    public Boolean realseConnection(Connection connection){
        try{
            lock.lock();
            System.out.println(Thread.currentThread().getName() + "released connection");
            connections.addLast(connection);
            condition.signal();
        }finally {
            lock.unlock();
        }
        return true;
    }

    public void setTimeout(Long timeout){
        this.timeout = timeout;
    }

    public static void main(String[] args) {
        ConnectionPool connectionPool = new ConnectionPool(1);
        for (int i = 0; i < 20; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Connection connection = connectionPool.getConnection();
                    if(connection == null){
                        return;
                    }
                    connection.commit();
                    connectionPool.realseConnection(connection);
                }
            }).start();
        }

    }
}


